/*
  Copyright 2010 Petri Kainulainen

  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for
  the specific language governing permissions and limitations under the License.
*/

package net.kainulainen.sitemesh;

import com.opensymphony.module.sitemesh.Config;
import com.opensymphony.module.sitemesh.Decorator;
import com.opensymphony.module.sitemesh.DecoratorMapper;
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.mapper.AbstractDecoratorMapper;

import java.util.Locale;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

/**
 * This decorator mapper implementation selects used decorator by using the
 * locale, which is stored in to the user's session. The name of the locale
 * attribute can be configured in the sitemesh.xml.
 * @author Petri Kainulainen
 */
public class SessionLocaleDecoratorMapper extends AbstractDecoratorMapper {

    public static final String PARAM_LOCALE_ATTRIBUTE_NAME = "localeAttributeName";

    private Logger logWriter = null;
    
    private String localeAttributeName = null;

    @Override
    public Decorator getDecorator(HttpServletRequest request, Page page) {
        logWriter.debug("Getting default decorator.");
        Decorator decorator = getDecoratorObject(request, page);

        try {
            decorator = findDecorator(request, decorator);
        }
        catch (Exception ex) {
            logWriter.info("An exception was thrown with message: " + ex.getMessage() + ". Falling back to default decorator: " + decorator.getName(), ex);    
        }

        return decorator;
    }

    public Decorator getDecoratorObject(HttpServletRequest request, Page page) {
        return super.getDecorator(request, page);
    }


    private Decorator findDecorator(HttpServletRequest request, Decorator parent) throws DecoratorNotFoundException, LocaleRetrievalException {
        logWriter.debug("Getting decorator by using locale stored in user's session");

        Locale usersLocale = getLocaleFromSession(request);
        String localeBasedDecoratorName = constructDecoratorName(parent, usersLocale);

        logWriter.debug("Getting named decorator with name: " + localeBasedDecoratorName);
        Decorator localeBasedDecorator = getNamedDecorator(request, localeBasedDecoratorName);

        if (localeBasedDecorator == null) {
            throw new DecoratorNotFoundException("Named decorator not found with name: " + localeBasedDecoratorName);
        }

        return localeBasedDecorator;
    }

    private Locale getLocaleFromSession(HttpServletRequest request) throws LocaleRetrievalException {
        logWriter.debug("Getting locale information from session parameter: " + localeAttributeName);
        HttpSession usersSession = request.getSession();
        Locale sessionStoredLocale = (Locale) usersSession.getAttribute(localeAttributeName);
        if (sessionStoredLocale == null) {
            throw new LocaleRetrievalException("No locale was found with key: " + localeAttributeName);
        }

        return sessionStoredLocale;
    }

    private String constructDecoratorName(Decorator parent, Locale usersLocale) {
        logWriter.debug("Constructing decorator name for locale: " + usersLocale.toString());
        StringBuilder decoratorNameConstructor = new StringBuilder();

        String defaultName = parent.getName();

        decoratorNameConstructor.append(defaultName);
        decoratorNameConstructor.append("_");
        decoratorNameConstructor.append(usersLocale.toString());

        return decoratorNameConstructor.toString();
    }

    @Override
    public void init(Config config, Properties properties, DecoratorMapper parent) throws InstantiationException {
        super.init(config, properties, parent);

        logWriter = Logger.getLogger(this.getClass());

        localeAttributeName = properties.getProperty(PARAM_LOCALE_ATTRIBUTE_NAME);
    }
}
